package com.un.ebs.invoice.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.un.ebs.contract.service.ContractService;
import com.un.ebs.core.exception.BusinessEntityNotFoundException;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.util.DateUtils;
import com.un.ebs.core.util.SecurityUtils;
import com.un.ebs.core.util.StringUtils;
import com.un.ebs.inventory.domain.*;
import com.un.ebs.inventory.enums.InventoryTypeEnum;
import com.un.ebs.inventory.service.BusinessRelationService;
import com.un.ebs.inventory.service.InventoryNoteService;
import com.un.ebs.inventory.service.InventoryNoteTypeService;
import com.un.ebs.inventory.service.InventoryService;
import com.un.ebs.invoice.CostCode;
import com.un.ebs.invoice.domain.*;
import com.un.ebs.invoice.dto.*;
import com.un.ebs.invoice.enums.InvoiceCashTypeEnum;
import com.un.ebs.invoice.enums.InvoiceTypeEnum;
import com.un.ebs.invoice.mapper.*;
import com.un.ebs.invoice.service.InvoiceNoteService;
import com.un.ebs.product.enums.ProductPurchaseTypeEnum;
import com.un.ebs.product.service.ProductSkuService;
import com.un.ebs.sale.dto.SaleOrderNotInvoiceView;
import com.un.ebs.sale.dto.SaleOrderVo;
import com.un.ebs.sale.service.SaleOrderService;
import com.un.ebs.sys.domain.DictionaryValueExt;
import com.un.ebs.sys.domain.Personnel;
import com.un.ebs.sys.service.*;
import com.un.ebs.workflow.service.WorkflowInstanceService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (InvoiceNote)表服务实现类
 *
 * @author liubo
 * @since 2020-09-27 11:06:42
 */
@Service("invoiceNoteService")
public class InvoiceNoteServiceImpl extends ServiceImpl<InvoiceNoteMapper, InvoiceNote> implements InvoiceNoteService {

    @Resource
    private InvoiceNoteItemMapper invoiceNoteItemMapper;

    @Resource
    private InvoiceNoteExtMapper invoiceNoteExtMapper;

    @Resource
    private InvoiceCashNoteMapper invoiceCashNoteMapper;

    @Resource
    private InvoiceNotBalanceExtMapper invoiceNotBalanceExtMapper;

    @Resource
    private InventoryService inventoryService;

    @Resource
    private UserService userService;

    @Resource
    private InvoiceNoteByPurchaseSumMapper invoiceNoteByPurchaseSumMapper;

    @Resource
    private InvoiceCashNoteItemMapper invoiceCashNoteItemMapper;

    @Resource
    private InvoiceNoteItemExtMapper invoiceNoteItemExtMapper;

    @Resource
    private InvoiceNoteItemAllExtMapper invoiceNoteItemAllExtMapper;

    @Resource
    private SaleNotInvoiceExtMapper saleNotInvoiceExtMapper;

    @Resource
    private InvoiceNoteByPurchaseMapper invoiceNoteByPurchaseMapper;

    @Resource
    private InvoiceNoteItemByPurchaseMapper invoiceNoteItemByPurchaseMapper;

    @Resource
    private DictionaryValueService dictionaryValueService;

    @Resource
    private ContractService contractService;

    @Resource
    private BusinessRelationService businessRelationService;

    @Resource
    private InvoiceCashNoteExtMapper invoiceCashNoteExtMapper;

    @Resource
    private InvoiceCashNoteItemExtMapper invoiceCashNoteItemExtMapper;

    @Resource
    private SaleOrderService saleOrderService;

    @Resource
    private InvoiceNoteItemBySaleExtMapper invoiceNoteItemBySaleExtMapper;

    @Resource
    private InventoryNoteTypeService inventoryNoteTypeService;

    @Resource
    private InventoryNoteService inventoryNoteService;

    @Resource
    private WorkflowInstanceService workflowInstanceService;

    @Resource
    private ConfigureService configureService;

    @Resource
    private WxService wxService;

    @Resource
    private PersonnelService personnelService;

    @Resource
    private ProductSkuService skuService;

    @Transactional
    @Override
    public void save(InvoiceNoteUpdateDto req) {

        if (StringUtils.isNullOrEmpty(req.getItems()) && StringUtils.isNullOrEmpty(req.getServiceItems())) {
            throw new BusinessException("发票原始单据不能为空。");
        }

//        ContractVo contractVo = contractService.queryViewByCode(req.getContractCode());
//        if (contractVo == null) {
//            throw new BusinessEntityNotFoundException(req.getContractCode(), "合同");
//        }
        AccountMonth accountMonth = inventoryService.queryAccountMonth(req.getInvoiceDate());
        if (accountMonth == null) {
            accountMonth = inventoryService.createAccountMonth(DateUtils.getYear(req.getInvoiceDate()), DateUtils.getMonth(req.getInvoiceDate()));
        }
        if (accountMonth.getSyncStatus()) {
            throw new BusinessException(String.format("当前会计期间【%s年%s月】的账务数据已同步至财务系统，不能创建【%s】的发票。", accountMonth.getAccountYear(), accountMonth.getAccountMonth(), DateUtils.formatDate(req.getInvoiceDate(), "yyyy-MM-dd")));
        }

        InvoiceNote note;
        if (!StringUtils.isNullOrEmpty(req.getId())) {
            note = baseMapper.selectById(req.getId());
        } else {
            note = new InvoiceNote();
            note.setCode(baseMapper.maxCode());
        }
        Personnel personnel = personnelService.queryById(req.getPersonnelId());
        if (personnel != null) {
            note.setPersonnelId(personnel.getId());
            note.setPersonnelName(personnel.getName());
        } else {
            throw new BusinessEntityNotFoundException(req.getPersonnelId(), "经办人");
        }
        note.setInvoiceType(req.getInvoiceType());
        note.setContractCode(req.getContractCode());
        note.setTaxRate(req.getTaxRate());
        note.setEntId(req.getEntId());
        note.setInvoiceDate(req.getInvoiceDate());
        note.setInvoiceNo(req.getInvoiceNo());
        note.setRemark(req.getRemark());
        note.insertOrUpdate();

        List<InventoryNoteItemBySale> list = inventoryNoteService.querySaleCanInvoice(req.getEntId(),"", -1, 1).getRecords();
        if (!StringUtils.isNullOrEmpty(req.getItems())) {
            for (InvoiceNoteItemDto noteItem : req.getItems()) {

                InvoiceNoteItem item = invoiceNoteItemMapper.selectById(noteItem.getId());
                if (item == null) {
                    item = new InvoiceNoteItem();
                    if (StringUtils.isNullOrEmpty(noteItem.getSkuId()) && req.getInvoiceType() != InvoiceTypeEnum.Purchase) {
                        throw new BusinessException("发票明细中的SKUId不能为空。");
                    }
                    if (noteItem.getCurrentQty() == 0 && req.getInvoiceType() != InvoiceTypeEnum.Purchase) {
                        throw new BusinessException("发票明细中的开票数量不能等于0.");
                    }
                }

                if (req.getInvoiceType() == InvoiceTypeEnum.Sale) {
                    Optional<InventoryNoteItemBySale> itemSale = list.stream().filter(s -> s.getSkuId().equals(noteItem.getSkuId())).filter(s -> s.getInventoryNoteId().equals(noteItem.getInventoryNoteId())).findFirst();
                    if (!itemSale.isPresent()) {
                        throw new BusinessException("没有找到可以开票的出库记录。");
                    }
                    if (itemSale.get().getInvoiceNotQty() < noteItem.getCurrentQty()) {
                        throw new BusinessException(String.format("当前开票数量【%s】不能大于未开票数量【%s】。", noteItem.getCurrentQty(), itemSale.get().getInvoiceNotQty()));
                    }
                    item.setCostPrice(itemSale.get().getPrice());
                    item.setContractPrice(itemSale.get().getContractPrice());
                    item.setSkuId(noteItem.getSkuId());
                    item.setInvoiceQty(item.getInvoiceQty() == null ? noteItem.getCurrentQty() : noteItem.getCurrentQty() + item.getInvoiceQty());
                }
                if (req.getInvoiceType() == InvoiceTypeEnum.Purchase) {
                    InventoryNoteExt purchaseNote = inventoryNoteService.queryViewById(noteItem.getInventoryNoteId());
                    if (purchaseNote == null) {
                        throw new BusinessException("指定了无效的采购入库单。");
                    }
                    if (!purchaseNote.getAuditStatus() && !purchaseNote.getSubmitStatus()) {
                        throw new BusinessException("指定的采购入库单未审核。");
                    }
                }
                item.setInventoryNoteId(noteItem.getInventoryNoteId());
                item.setNoteId(note.getId());
                item.insertOrUpdate();
            }
        }
        if (!StringUtils.isNullOrEmpty(req.getServiceItems())) {
            for (InvoiceNoteItemBySaleOrderDto noteItem : req.getServiceItems()) {
                InvoiceNoteByServiceResult result = baseMapper.queryCanServiceInvoice(noteItem.getSaleOrderId(),noteItem.getSkuId());
                if(result.getCanInvoiceMoney()<=0){
                    throw new BusinessException("当前销售订单已没有可开票金额。");
                }
//                SaleOrderVo order = saleOrderService.queryViewById(noteItem.getSaleOrderId());
//                if (order == null) {
//                    throw new BusinessEntityNotFoundException(noteItem.getSaleOrderId(), "销售订单");
//                }
//                if (!order.getSubmitStatus()) {
//                    throw new BusinessException("销售订单没有提交。");
//                }

                if (skuService.queryViewById(noteItem.getSkuId()).getPurchaseType() != ProductPurchaseTypeEnum.Default) {
                    throw new BusinessException("销售订单中的产品为外部采购或内部生产，不可以直接进行此操作。");
                }

                InvoiceNoteBySale obj = new InvoiceNoteBySale();
                obj.setSaleOrderId(noteItem.getSaleOrderId());
                obj.setNoteId(note.getId());
                obj.setSkuId(noteItem.getSkuId());
                obj.setInvoiceMoney(noteItem.getCurrentQty());
                obj.insertOrUpdate();
            }
        }
    }

    @Override
    public void delete(String id) {
        InvoiceNote note = baseMapper.selectById(id);
        if (note.getSubmitStatus()) {
            throw new BusinessException("发票申请已提交。");
        }
        note.deleteById();
    }

    @Override
    public void updateFinanceCode(String id, String financeId, String financeCode) {
        baseMapper.updateFinanceStatus(id, financeId, financeCode);
    }

    @Transactional
    @Override
    public String submit(String id) {
        InvoiceNote note = baseMapper.selectById(id);
        if (note.getSubmitStatus()) {
            throw new BusinessException("发票申请已提交。");
        }
        AccountMonth accountMonth = inventoryService.queryAccountMonth(note.getInvoiceDate());
        if (accountMonth == null) {
            accountMonth = inventoryService.createAccountMonth(DateUtils.getYear(note.getInvoiceDate()), DateUtils.getMonth(note.getInvoiceDate()));
        }
        if (accountMonth.getSyncStatus()) {
            throw new BusinessException(String.format("当前会计期间【%s年%s月】的账务数据已同步至财务系统，不能进行此操作。", accountMonth.getAccountYear(), accountMonth.getAccountMonth()));
        }
        note.setSubmitAt(SecurityUtils.getUserContent().getId());
        note.setSubmitAtName(SecurityUtils.getUserContent().getPersonnelName());
        note.setSubmitTime(new Date());
        note.setSubmitStatus(true);

        InventoryNoteTypeExt noteTypeExt;
        InventoryTypeEnum inventoryType;
        switch (note.getInvoiceType()) {
            case Purchase:
                noteTypeExt = inventoryNoteTypeService.queryOneByType(InventoryTypeEnum.INVOICE_PURCHASE);
                inventoryType = InventoryTypeEnum.INVOICE_PURCHASE;
                break;
            case Sale:
                noteTypeExt = inventoryNoteTypeService.queryOneByType(InventoryTypeEnum.INVOICE_SALE);
                inventoryType = InventoryTypeEnum.INVOICE_SALE;
                break;
            default:
                throw new BusinessException("发票类型不正确。");
        }

        // 如果定义了审批流程，则开始流程
        String workflowInstanceId = null;
        if (!StringUtils.isNullOrEmpty(noteTypeExt.getWorkflowId())) {
            workflowInstanceId = workflowInstanceService.start(noteTypeExt.getWorkflowId(), inventoryType, id, note.getCode().toString());
            note.setWorkflowPassStatus(false);
            note.setWorkflowInstanceId(workflowInstanceId);
        } else {
            note.setWorkflowPassStatus(true);
        }
        note.updateById();
        return workflowInstanceId;
    }

    @Override
    public void submitCancel(String id) {
        InvoiceNote note = baseMapper.selectById(id);
        if (!note.getSubmitStatus()) {
            throw new BusinessException("发标申请未提交，哪来的撤销提交?");
        }
        if (note.getAuditStatus()) {
            throw new BusinessException("销售发票已审核，不能撤销提交。");
        }
        note.setSubmitAt(null);
        note.setSubmitAtName(null);
        note.setSubmitTime(null);
        note.setSubmitStatus(false);

        if (!StringUtils.isNullOrEmpty(note.getWorkflowInstanceId())) {
            workflowInstanceService.close(note.getWorkflowInstanceId(), "销售发票撤销提交", false);
            note.setWorkflowPassStatus(false);
            note.setWorkflowInstanceId(null);
        }

        note.updateById();
    }

    @Transactional
    @Override
    public String audit(InvoiceAuditDto req) {
        InvoiceNote note = baseMapper.selectById(req.getId());
        if (note == null) {
            throw new BusinessEntityNotFoundException(req.getId(), "发票");
        }
        if (!note.getSubmitStatus()) {
            throw new BusinessException("发票未提交。");
        }
        if (note.getAuditStatus()) {
            throw new BusinessException("发票申请已审核。");
        }
        if (!note.getWorkflowPassStatus()) {
            throw new BusinessException("审批流程通过后才能执行此操作。");
        }
        AccountMonth accountMonth = inventoryService.queryAccountMonth(req.getInvoiceDate() == null ? new Date() : req.getInvoiceDate());
        if (accountMonth.getSyncStatus()) {
            throw new BusinessException(String.format("当前会计期间【%s年%s月】的账务数据已同步至财务系统，不能进行此操作。", accountMonth.getAccountYear(), accountMonth.getAccountMonth()));
        }
        note.setAuditAt(SecurityUtils.getUserContent().getId());
        note.setAuditAtName(SecurityUtils.getUserContent().getPersonnelName());
        note.setAuditTime(new Date());
        note.setAuditStatus(true);
        note.setInvoiceDate(req.getInvoiceDate() == null ? new Date() : req.getInvoiceDate());
        note.setInvoiceNo(req.getInvoiceNo());
        note.setSourceMoney(req.getSourceMoney());
        note.setTaxMoney(req.getTaxMoney());
        note.updateById();

        BigDecimal realMoney = new BigDecimal(req.getTaxMoney()).add(new BigDecimal(req.getSourceMoney()));
        BigDecimal planMoney;
        if (note.getInvoiceType() == InvoiceTypeEnum.Sale) {
            //planMoney = new BigDecimal(queryViewById(req.getId()).getSaleMoney());
            planMoney = new BigDecimal(queryViewById(req.getId()).getInvoiceMoney());
        } else {
            planMoney = new BigDecimal(baseMapper.queryPurchaseById(req.getId()).getInvoiceMoney());
        }
        BigDecimal diff = realMoney.setScale(2, RoundingMode.HALF_UP).subtract(planMoney.setScale(2, RoundingMode.HALF_UP)).abs();
        if (diff.doubleValue() > 0.5d) {
            throw new BusinessException("实际发票与发票申请的价税合计不能超过0.5，当前差异：" + diff.doubleValue());
        }

        return note.getWorkflowInstanceId();
    }

    @Override
    public void auditCancel(String id) {
        InvoiceNote note = baseMapper.selectById(id);
        if (note == null) {
            throw new BusinessEntityNotFoundException(id, "发票");
        }
        if (!note.getAuditStatus()) {
            throw new BusinessException("发票未审核。");
        }
        if (inventoryNoteService.isCloseAccount(note.getSubmitTime())) {
            throw new BusinessException(String.format("【%s年%s月】的会计期间已关账，不能执行此操作。", DateUtils.getYear(new Date()), DateUtils.getMonth(new Date())));
        }

        note.setAuditAt(null);
        note.setAuditAtName(null);
        note.setAuditTime(null);
        note.setAuditStatus(false);
        note.updateById();
    }

    @Transactional
    @Override
    public void back(String id, String remark) {
        InvoiceNote note = baseMapper.selectById(id);
        if (!note.getAuditStatus()) {
            throw new BusinessException("发票没有审核，无需进行此操作。");
        }
        Calendar cal = Calendar.getInstance();
        Integer intYearMonth = Integer.parseInt(DateUtils.formatDate(note.getAuditTime(), "yyyyMM"));
        Integer intNow = Integer.parseInt(cal.get(Calendar.YEAR) + String.format("%02d", cal.get(Calendar.MONTH)));
        if (intYearMonth >= intNow) {
            throw new BusinessException("本月记账的发票可直接撤销记账。");
        }

        /**
         * 对发票反冲
         */
        InvoiceNote obj = new InvoiceNote();
        obj.setCode(baseMapper.maxCode());
        obj.setPersonnelId(note.getPersonnelId());
        obj.setPersonnelName(note.getPersonnelName());
        obj.setInvoiceNo(note.getInvoiceNo());
        obj.setInvoiceType(note.getInvoiceType());
        obj.setInvoiceDate(new Date());
        obj.setTaxMoney(note.getTaxMoney());
        obj.setTaxRate(note.getTaxRate());
        obj.setEntId(note.getEntId());
        obj.setIsBack(true);
        obj.setRemark(remark);
        obj.insert();

        LambdaQueryWrapper<InvoiceNoteItem> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteItem::getNoteId, id);
        for (InvoiceNoteItem item : invoiceNoteItemMapper.selectList(lq)) {
            InvoiceNoteItem newItem = new InvoiceNoteItem();
            newItem.setSkuId(item.getSkuId());
            newItem.setInvoiceQty(item.getInvoiceQty());
            newItem.setInventoryNoteId(item.getInventoryNoteId());
            newItem.setCostPrice(item.getCostPrice());
            newItem.setContractPrice(item.getContractPrice());
            newItem.setNoteId(obj.getId());
            newItem.insert();
        }

        note.setBackNoteId(obj.getId());
        note.updateById();
    }

    @Override
    public void workflowPass(String noteId, String workflowInstanceId) {
        InvoiceNote note = baseMapper.selectById(noteId);
        if (note == null) {
            throw new BusinessException("流程结束时，没有找到相应的发票信息。");
        }
        if (!workflowInstanceId.equals(note.getWorkflowInstanceId())) {
            throw new BusinessException("当前发票号的审核流程实例与实际不符，操作失败。");
        }
        note.setWorkflowPassStatus(true);
        note.updateById();
    }

    @Override
    public InvoiceCashNote cash(String entId, Double money, Date cashDate, InvoiceCashTypeEnum type, String moneyDict, String remark) {
        EntRelationExt ent = businessRelationService.queryByEnt(entId);
        if (ent == null) {
            throw new BusinessEntityNotFoundException(entId, "往来单位");
        }

        Optional<DictionaryValueExt> dictValue = dictionaryValueService.queryValueByKey(CostCode.money_type_dict).stream().filter(s -> s.getValue().equals(moneyDict)).findFirst();
        if (!dictValue.isPresent()) {
            throw new BusinessException(String.format("指定的字典【%s】值【%s】不正确。", CostCode.money_type_dict, moneyDict));
        }

        InvoiceCashNote cashNote = new InvoiceCashNote();

        if (cashDate == null) {
            cashNote.setCashTime(new Date());
        } else {
            cashNote.setCashTime(cashDate);
        }

        cashNote.setEntId(entId);
        cashNote.setCashMoney(money);
        cashNote.setCashType(type);
        cashNote.setMoneyType(moneyDict);
        cashNote.setPersonnelId(SecurityUtils.getUserContent().getPersonnelId());
        cashNote.setPersonnelName(SecurityUtils.getUserContent().getPersonnelName());
        cashNote.setRemark(remark);
        cashNote.insert();

        sendMessage(cashNote);
        return cashNote;
    }

    private void sendMessage(InvoiceCashNote note) {
        String templateId = configureService.getValueByCode(CostCode.customer_invoice_cash_id);
        InvoiceCashNoteExt obj = queryCashViewById(note.getId());
        if (obj == null) {
            return;
        }

        List<String> userIds = contractService.queryPersonUserIds(note.getEntId());
        for (String id : userIds) {
            wxService.sendTemplateMessage(SecurityUtils.getTenantId(), id, templateId, "有新的客户回款！", obj.getEntName(), DateUtils.formatDate(obj.getCashTime(), "yyyy-MM-dd"), obj.getCashMoney().toString(), obj.getPersonnelNames(), obj.getRemark(), "");
        }
        wxService.sendTemplateMessage(SecurityUtils.getTenantId(), "9bddd1d360947dbd79a39499148a7645", templateId, "有新的客户回款！", obj.getEntName(), DateUtils.formatDate(obj.getCashTime(), "yyyy-MM-dd"), obj.getCashMoney().toString(), obj.getPersonnelNames(), "请知悉。", "");

    }

    @Override
    public void cashClaim(String cashNoteId, String invoiceNoteId, Double claimMoney) {
        InvoiceCashNoteExt cashNote = invoiceCashNoteExtMapper.selectById(cashNoteId);
        if (cashNote == null) {
            throw new BusinessEntityNotFoundException(cashNoteId, "现金记录");
        }
        if (cashNote.getSurplusMoney() < claimMoney) {
            throw new BusinessException("当前认领金额不能大于剩余金额。");
        }

        InvoiceNoteExt invoiceNote = queryViewById(invoiceNoteId);// baseMapper.selectById(invoiceNoteId);
        if (invoiceNote == null) {
            throw new BusinessEntityNotFoundException(invoiceNoteId, "发票");
        }
        if (!invoiceNote.getAuditStatus()) {
            throw new BusinessException("发票没有审核，不能进行此操作。");
        }
        if (!cashNote.getEntId().equals(invoiceNote.getEntId())) {
            throw new BusinessException("现金记录与发票不是同一个往来单位。");
        }
        double diffMoney = new BigDecimal(invoiceNote.getInvoiceMoney()).subtract(new BigDecimal(invoiceNote.getCashMoney())).doubleValue();
        if (new BigDecimal(diffMoney).setScale(2, RoundingMode.HALF_UP).doubleValue() < new BigDecimal(claimMoney).setScale(2, RoundingMode.HALF_UP).doubleValue()) {
            throw new BusinessException(String.format("当前认领金额[%s]不能大于发票剩余未认领金额[%s]。", claimMoney, diffMoney));
        }

        InvoiceCashNoteItem item = new InvoiceCashNoteItem();
        item.setCashMoney(claimMoney);
        item.setInvoiceCashNoteId(cashNoteId);
        item.setInvoiceNoteId(invoiceNoteId);
        item.insert();
    }

    @Override
    public void deleteCash(String id) {
        InvoiceCashNote cashNote = invoiceCashNoteMapper.selectById(id);
        if (cashNote == null) {
            throw new BusinessEntityNotFoundException(id, "现金收/付款");
        }

        LambdaQueryWrapper<InvoiceCashNoteItem> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceCashNoteItem::getInvoiceCashNoteId, id);
        if (invoiceCashNoteItemMapper.selectCount(lq) > 0) {
            throw new BusinessException("现金收/付款已被认领，不能删除。");
        }

        if (!cashNote.getCreateAt().equals(SecurityUtils.getUserContent().getId())) {
            throw new BusinessException("此笔数据只能由 【" + cashNote.getCreateAtName() + "】 执行此操作。");
        }

        cashNote.deleteById();
    }

    @Override
    public void deleteCashClaim(String id) {
        InvoiceCashNoteItem obj = invoiceCashNoteItemMapper.selectById(id);
        if (obj == null) {
            throw new BusinessEntityNotFoundException(id, "认领记录");
        }
        if (!obj.getCreateAt().equals(SecurityUtils.getUserContent().getId())) {
            throw new BusinessException("此认领记录只能由 【" + obj.getCreateAtName() + "】 执行此操作。");
        }
        obj.deleteById();
    }

    @Override
    public InvoiceCashNoteExt queryCashViewById(String id) {
        return invoiceCashNoteExtMapper.selectById(id);
    }

    private List<String> getPowerRoles() {
        List<String> roles = new ArrayList<>();
        roles.add("1600-S02");
        roles.add("1600-F02");
        roles.add("1600-F03");
        return roles;
    }

    @Override
    public IPage<InvoiceCashNoteExt> queryCash(String entId, Integer accountYear, Integer accountMonth, int pageSize, int pageIndex) {
        Page<InvoiceCashNoteExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<InvoiceCashNoteExt> lq = Wrappers.lambdaQuery();
        if (!StringUtils.isNullOrEmpty(entId)) {
            lq.eq(InvoiceCashNoteExt::getEntId, entId);
        }
        if (accountYear != null) {
            lq.eq(InvoiceCashNoteExt::getCashYear, accountYear);
        }
        if (accountMonth != null) {
            lq.eq(InvoiceCashNoteExt::getCashMonth, accountMonth);
        }

        List<String> roles = getPowerRoles();
        if (userService.queryCurrRoles().stream().filter(s -> roles.contains(s.getCode())).count() <= 0) {
            lq.in(InvoiceCashNoteExt::getPersonnelIds, SecurityUtils.getUserContent().getPersonnelId());
        }
        lq.orderByDesc(InvoiceCashNoteExt::getCashTime);
        return invoiceCashNoteExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<InvoiceCashNoteExt> queryCash(int pageSize, int pageIndex) {
        Page<InvoiceCashNoteExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<InvoiceCashNoteExt> lq = Wrappers.lambdaQuery();
        List<String> roles = getPowerRoles();
        if (userService.queryCurrRoles().stream().filter(s -> roles.contains(s.getCode())).count() <= 0) {
            lq.in(InvoiceCashNoteExt::getPersonnelIds, SecurityUtils.getUserContent().getPersonnelId());
        }
        lq.ne(InvoiceCashNoteExt::getSurplusMoney, 0);
        lq.orderByDesc(InvoiceCashNoteExt::getCashTime);
        return invoiceCashNoteExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<InvoiceNoteExt> queryNotCash(String entId, int pageSize, int pageIndex) {
        Page<InvoiceNoteExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<InvoiceNoteExt> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteExt::getEntId, entId);
        List<String> roles = getPowerRoles();
        if (userService.queryCurrRoles().stream().filter(s -> roles.contains(s.getCode())).count() <= 0) {
            lq.in(InvoiceNoteExt::getPersonnelId, SecurityUtils.getUserContent().getPersonnelId());
        }
        lq.apply(" invoice_money > cash_money ");
        lq.orderByAsc(InvoiceNoteExt::getInvoiceCode);
        return invoiceNoteExtMapper.selectPage(page, lq);
    }

    @Override
    public List<InvoiceCashNoteItemExt> queryCashClaim(String cashNoteId) {
        LambdaQueryWrapper<InvoiceCashNoteItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceCashNoteItemExt::getInvoiceCashNoteId, cashNoteId);
        lq.orderByDesc(InvoiceCashNoteItemExt::getCreateTime);
        return invoiceCashNoteItemExtMapper.selectList(lq);
    }

    @Override
    public List<InvoiceCashNoteItemExt> queryCashClaimByInvoice(String invoiceNoteId) {
        LambdaQueryWrapper<InvoiceCashNoteItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceCashNoteItemExt::getInvoiceNoteId, invoiceNoteId);
        lq.orderByDesc(InvoiceCashNoteItemExt::getCreateTime);
        return invoiceCashNoteItemExtMapper.selectList(lq);
    }

    @Override
    public IPage<InvoiceNoteExt> queryMyInvoice(Boolean isCash, Integer pageSize, Integer pageIndex) {
        IPage<InvoiceNoteExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<InvoiceNoteExt> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteExt::getPersonnelId, SecurityUtils.getUserContent().getPersonnelId());
        if (isCash != null) {
            if (isCash) {
                lq.eq(InvoiceNoteExt::getCanCashMoney, 0);
            } else {
                lq.ne(InvoiceNoteExt::getCanCashMoney, 0);
            }
        }
        return invoiceNoteExtMapper.selectPage(page, lq);
    }

    @Override
    public InvoiceNoteVo queryViewById(String id) {
        if (StringUtils.isNullOrEmpty(id)) {
            return null;
        }
        InvoiceNoteExt note = invoiceNoteExtMapper.selectViewById(id);
        if (note == null) {
            throw new BusinessEntityNotFoundException(id, "发票");
        }

        InvoiceNoteVo ret = new InvoiceNoteVo();
        BeanUtils.copyProperties(note, ret);
        ret.setItems(invoiceNoteItemExtMapper.selectByNoteId(id));
        return ret;
    }

    @Override
    public IPage<InvoiceNoteExt> query(InvoiceTypeEnum invoiceType, Integer accountYear, Integer accountMonth, Integer pageSize, Integer pageIndex) {
        if (accountYear == null) {
            throw new BusinessException("年份不能为空。");
        }
        IPage<InvoiceNoteExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<InvoiceNoteExt> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteExt::getInvoiceType, invoiceType);
        lq.eq(InvoiceNoteExt::getAccountYear, accountYear);
        if (accountMonth != null) {
            lq.eq(InvoiceNoteExt::getAccountMonth, accountMonth);
        }
        lq.orderByDesc(InvoiceNoteExt::getInvoiceCode);
        return invoiceNoteExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<InvoiceNoteExt> queryWaitAudit(Integer pageSize, Integer pageIndex) {
        IPage<InvoiceNoteExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<InvoiceNoteExt> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteExt::getInvoiceType, InvoiceTypeEnum.Sale);
        //lq.eq(InvoiceNoteExt::getAuditStatus, false);
        lq.eq(InvoiceNoteExt::getSubmitStatus, true);
        lq.orderByDesc(InvoiceNoteExt::getInvoiceCode);
        return invoiceNoteExtMapper.selectPage(page, lq);
    }

    @Override
    public InvoiceCashVo queryCashInfo(String cashId) {
        InvoiceCashVo ret = new InvoiceCashVo();
        InvoiceCashNoteExt obj = queryCashViewById(cashId);
        ret.setCashId(obj.getId());
        ret.setEntId(obj.getEntId());
        ret.setEntName(obj.getEntName());
        ret.setCurrCashMoney(obj.getCashMoney());
        ret.setCurrCashTime(obj.getCashTime());
        ret.setPersonnelName(obj.getPersonnelName());
        ret.setMoneyDictDesc(obj.getMoneyTypeDesc());

        LambdaQueryWrapper<InvoiceCashNoteExt> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceCashNoteExt::getEntId, obj.getEntId());
        lq.ne(InvoiceCashNoteExt::getSurplusMoney, 0);
        ret.setTotalSurplusMoney(invoiceCashNoteExtMapper.selectList(lq).stream().mapToDouble(s -> s.getSurplusMoney()).sum());

        LambdaQueryWrapper<InvoiceNoteExt> lqInvoice = Wrappers.lambdaQuery();
        lqInvoice.eq(InvoiceNoteExt::getEntId, obj.getEntId());
        lqInvoice.eq(InvoiceNoteExt::getSubmitStatus, true);
        lqInvoice.ne(InvoiceNoteExt::getCanCashMoney, 0);
        ret.setTotalCanCashMoney(invoiceNoteExtMapper.selectList(lqInvoice).stream().mapToDouble(s -> s.getCanCashMoney()).sum());

        LambdaQueryWrapper<InvoiceCashNoteItemExt> lqCashNote = Wrappers.lambdaQuery();
        lqCashNote.eq(InvoiceCashNoteItemExt::getInvoiceCashNoteId, cashId);
        ret.setItems(invoiceCashNoteItemExtMapper.selectList(lqCashNote));

        return ret;
    }

    @Override
    public IPage<InvoiceNoteByPurchase> queryPurchase(Integer accountYear, Integer accountMonth, Integer pageSize, Integer pageIndex) {
        if (accountYear == null) {
            throw new BusinessException("年份不能为空。");
        }
        IPage<InvoiceNoteByPurchase> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<InvoiceNoteByPurchase> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteByPurchase::getInvoiceType, InvoiceTypeEnum.Purchase);
        lq.eq(InvoiceNoteByPurchase::getAccountYear, accountYear);
        if (accountMonth != null) {
            lq.eq(InvoiceNoteByPurchase::getAccountMonth, accountMonth);
        }
        //lq.eq(InvoiceNoteByPurchase::getSubmitStatus,true);
        //lq.eq(InvoiceNoteByPurchase::getAuditStatus,true);
        lq.orderByDesc(InvoiceNoteByPurchase::getInvoiceCode);
        return invoiceNoteByPurchaseMapper.selectPage(page, lq);
    }

    @Override
    public List<InvoiceNoteByPurchaseSum> queryPurchaseSum(int accountYear, int accountMonth) {
        LambdaQueryWrapper<InvoiceNoteByPurchaseSum> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteByPurchaseSum::getAccountYear, accountYear);
        lq.eq(InvoiceNoteByPurchaseSum::getAccountMonth, accountMonth);
        return invoiceNoteByPurchaseSumMapper.selectList(lq);
    }

    @Override
    public List<InvoiceNoteItemByPurchase> queryPurchaseItem(String noteId) {
        LambdaQueryWrapper<InvoiceNoteItemByPurchase> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteItemByPurchase::getInvoiceNoteId, noteId);
        lq.orderByAsc(InvoiceNoteItemByPurchase::getCode);
        return invoiceNoteItemByPurchaseMapper.selectList(lq);
    }

    @Override
    public List<InvoiceNoteItemExt> queryItem(String noteId) {
        LambdaQueryWrapper<InvoiceNoteItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteItemExt::getInvoiceNoteId, noteId);
        lq.orderByAsc(InvoiceNoteItemExt::getCode);
        return invoiceNoteItemExtMapper.selectList(lq);
    }

    @Override
    public IPage<InvoiceNoteItemBySaleExt> queryItemBySale(String noteId, int pageSize, int pageIndex) {
        Page<InvoiceNoteItemBySaleExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<InvoiceNoteItemBySaleExt> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteItemBySaleExt::getNoteId, noteId);
        return invoiceNoteItemBySaleExtMapper.selectPage(page, lq);
    }

    @Override
    public List<InvoiceNoteItemExt> queryItemBySaleContractCode(String contractCode) {
        LambdaQueryWrapper<InvoiceNoteItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteItemExt::getContractCode, contractCode);
        lq.eq(InvoiceNoteItemExt::getIsDelete, false);
        lq.eq(InvoiceNoteItemExt::getSubmitStatus, true);
        return invoiceNoteItemExtMapper.selectList(lq);
    }

    @Override
    public List<InvoiceNoteExt> queryNotSendFinance(InvoiceTypeEnum invoiceType, int accountYear, int accountMonth) {
        LambdaQueryWrapper<InvoiceNoteExt> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteExt::getInvoiceType, invoiceType);
        lq.eq(InvoiceNoteExt::getAccountYear, accountYear);
        lq.eq(InvoiceNoteExt::getAccountMonth, accountMonth);
        lq.eq(InvoiceNoteExt::getSubmitStatus, true);
        lq.eq(InvoiceNoteExt::getAuditStatus, true);
        lq.isNull(InvoiceNoteExt::getFinanceId);
        return invoiceNoteExtMapper.selectList(lq);
    }

    @Override
    public IPage<InvoiceNoteItemAllExt> queryItem(InvoiceItemQueryRequest req) {
        Page<InvoiceNoteItemAllExt> page = new Page<>(req.getPageIndex(), req.getPageSize());
        LambdaQueryWrapper<InvoiceNoteItemAllExt> lq = Wrappers.lambdaQuery();
        lq.eq(InvoiceNoteItemAllExt::getSubmitStatus, true);
        lq.eq(InvoiceNoteItemAllExt::getAuditStatus, true);
        if (!StringUtils.isNullOrEmpty(req.getSkuCode())) {
            lq.eq(InvoiceNoteItemAllExt::getSkuCode, req.getSkuCode());
        }
        if (!StringUtils.isNullOrEmpty(req.getEntId())) {
            lq.eq(InvoiceNoteItemAllExt::getCustomerEntId, req.getEntId());
        }
        lq.eq(InvoiceNoteItemAllExt::getAccountYear, req.getAccountYear());
        if (req.getAccountMonth() != null) {
            lq.eq(InvoiceNoteItemAllExt::getAccountMonth, req.getAccountMonth());
        }
        lq.orderByDesc(InvoiceNoteItemAllExt::getAccountDate);
        return invoiceNoteItemAllExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<SaleNotInvoiceExt> querySaleNotInvoice(int pageSize, int pageIndex) {
        Page<SaleNotInvoiceExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<SaleNotInvoiceExt> lq = Wrappers.lambdaQuery();
        lq.orderByDesc(SaleNotInvoiceExt::getBusinessMoney);
        return saleNotInvoiceExtMapper.selectPage(page, lq);
    }

    @Override
    public List<InvoiceBalanceDto> queryInvoiceBalance(String entName, InvoiceTypeEnum invoiceType) {
        if (invoiceType == InvoiceTypeEnum.Sale) {
            LambdaQueryWrapper<InvoiceNotBalanceExt> lq = Wrappers.lambdaQuery();
            if (!StringUtils.isNullOrEmpty(entName)) {
                lq.like(InvoiceNotBalanceExt::getEntName, entName);
            }
            return invoiceNotBalanceExtMapper.selectList(lq).stream().map(s -> {
                InvoiceBalanceDto obj = new InvoiceBalanceDto();
                obj.setEntId(s.getEntId());
                obj.setEntName(s.getEntName());
                obj.setCanMoney(s.getCanMoney());
                obj.setCanQty(s.getCanInvoiceNotQty());
                return obj;
            }).collect(Collectors.toList());
        } else if (invoiceType == InvoiceTypeEnum.Purchase) {
            return null;
        } else {
            return null;
        }
    }

    @Override
    public List<SaleOrderNotInvoiceView> querySaleNotInvoiceByService() {
        List<InvoiceNoteByServiceResult> list  = baseMapper.queryCanServiceInvoiceList(userService.getUserContext().getTenantId());
        List<SaleOrderNotInvoiceView> result = new ArrayList<>();
        for (InvoiceNoteByServiceResult item : list){
            SaleOrderNotInvoiceView obj = new SaleOrderNotInvoiceView();
            obj.setOrderId(item.getOrderId());
            obj.setOrderCode(item.getOrderCode());
            obj.setContractCode(item.getContractCode());
            obj.setSkuId(item.getSkuId());
            obj.setSkuCode(item.getSkuCode());
            obj.setSkuName(item.getSkuName());
            obj.setQty(1d);
            obj.setMoney(item.getCanInvoiceMoney());
            obj.setEntId(item.getCustomerEntId());
            obj.setEntName(item.getCustomerEntName());
            result.add(obj);
        }
        return result;
        //return saleOrderService.querySaleOrderNotInvoiceByService();
    }

    @Override
    public List<AccountAgeDto> queryAccountAge() {
        return baseMapper.queryAccountAge();
    }
}